/**
 * JSON转PPT转换器
 * 基于模板将JSON数据转换为PowerPoint演示文稿
 */

import PptxGenJs from 'pptxgenjs';
import { promises as fs } from 'fs';
import { dirname } from 'path';
import type { 
  JsonToPptOptions, 
  PptConversionResult,
  JsonToPptParams,
  GeneratePptFromTemplateParams,
  PptTemplate,
  SlideTemplate,
  PlaceholderConfig 
} from './types.js';
import { PptTemplateManager } from './template.js';
import { createChildLogger, createErrorLogContext } from '../../../utils/logger.js';

export class JsonToPptConverter {
  private logger = createChildLogger('JsonToPptConverter');
  private templateManager: PptTemplateManager;

  constructor(templatesDir?: string) {
    this.templateManager = new PptTemplateManager(templatesDir);
  }

  /**
   * 转换JSON数据为PPT
   */
  async convertToPpt(params: JsonToPptParams): Promise<PptConversionResult> {
    const { data, templateName, outputPath, options = {} } = params;

    try {
      this.logger.info('Starting JSON to PPT conversion', {
        templateName,
        dataLength: data.length,
        outputPath,
        options
      });

      // 确保输出目录存在
      await fs.mkdir(dirname(outputPath), { recursive: true });

      // 加载模板
      const template = await this.templateManager.loadTemplate(templateName);

      // 创建PPT
      const ppt = this.createPpt(template, options);

      // 生成幻灯片
      await this.generateSlidesFromData(ppt, template, data, options);

      // 保存PPT
      await this.savePpt(ppt, outputPath);

      // 获取文件大小
      const stats = await fs.stat(outputPath);

      const result: PptConversionResult = {
        success: true,
        outputPath,
        size: stats.size,
        slideCount: this.calculateSlideCount(template, data),
        message: `成功生成PPT，基于模板"${templateName}"生成${this.calculateSlideCount(template, data)}页幻灯片`
      };

      this.logger.info('JSON to PPT conversion completed', result);
      return result;

    } catch (error) {
      this.logger.error(
        'JSON to PPT conversion failed',
        createErrorLogContext(error, { templateName, outputPath })
      );
      throw error;
    }
  }

  /**
   * 从模板生成PPT
   */
  async generateFromTemplate(params: GeneratePptFromTemplateParams): Promise<PptConversionResult> {
    return this.convertToPpt({
      data: params.data,
      templateName: params.templateName,
      outputPath: params.outputPath,
      options: params.options
    });
  }

  /**
   * 创建PPT实例
   */
  private createPpt(template: PptTemplate, options: JsonToPptOptions): PptxGenJs {
    const ppt = new PptxGenJs();

    // 设置PPT属性
    ppt.author = options.author || 'Test Case Writer';
    ppt.title = options.title || template.name || 'JSON转PPT演示';
    ppt.subject = template.description || 'Generated from JSON data';

    // 设置布局
    if (options.size === 'widescreen') {
      ppt.layout = 'LAYOUT_WIDE';
    }

    // 应用模板全局样式
    if (template.styles) {
      this.applyGlobalStyles(ppt, template.styles);
    }

    // 设置主题
    if (options.theme) {
      this.applyTheme(ppt, options.theme);
    }

    return ppt;
  }

  /**
   * 从数据生成幻灯片
   */
  private async generateSlidesFromData(
    ppt: PptxGenJs, 
    template: PptTemplate, 
    data: any[], 
    options: JsonToPptOptions
  ): Promise<void> {
    // 将模板名称添加到选项中以便在后续方法中使用
    const extendedOptions = { ...options, templateName: template.name };
    let slideNumber = 1; // 追踪幻灯片编号
    
    // 处理每个幻灯片模板
    for (const slideTemplate of template.slides) {
      if (slideTemplate.type === 'title') {
        // 标题页只生成一次
        await this.createTitleSlide(ppt, slideTemplate, data[0] || {}, extendedOptions, template, slideNumber++);
      } else if (slideTemplate.type === 'section') {
        // 章节页只生成一次
        await this.createSectionSlide(ppt, slideTemplate, data[0] || {}, extendedOptions, template, slideNumber++);
      } else {
        // 内容页为每个数据项生成一页
        for (const itemData of data) {
          await this.createContentSlide(ppt, slideTemplate, itemData, extendedOptions, template, slideNumber++);
        }
      }
    }
  }

  /**
   * 创建标题幻灯片
   */
  private async createTitleSlide(
    ppt: PptxGenJs, 
    slideTemplate: SlideTemplate, 
    data: any, 
    options: JsonToPptOptions,
    template?: PptTemplate,
    slideNumber?: number
  ): Promise<void> {
    const slide = ppt.addSlide();

    // 应用模板样式
    if (!template) {
      template = await this.templateManager.loadTemplate(options.templateName || 'default');
    }
    if (template.styles?.backgroundColor) {
      slide.background = { color: template.styles.backgroundColor.replace('#', '') };
      this.logger.debug('Applied background color to title slide', { 
        backgroundColor: template.styles.backgroundColor,
        processed: template.styles.backgroundColor.replace('#', '')
      });
    }
    
    // 添加装饰元素
    await this.addDecorationElements(slide, ppt, template);

    // 添加标题
    const title = this.templateManager.replacePlaceholders(slideTemplate.title, data);
    
    const titleOptions = {
      x: 1,
      y: slideTemplate.layout?.titlePosition === 'center' ? 3 : 1,
      w: 11.33, // 16:9宽度适配，留出边距
      h: 1.5,
      fontSize: options.fontSize?.title || 32,
      bold: true,
      color: template.styles?.titleColor?.replace('#', '') || '16537e',
      align: slideTemplate.layout?.contentAlignment || 'center'
    };

    slide.addText(title, titleOptions);

    // 处理占位符
    if (slideTemplate.placeholders) {
      await this.addPlaceholdersToSlide(slide, slideTemplate.placeholders, data, ppt);
    }
  }

  /**
   * 创建章节幻灯片
   */
  private async createSectionSlide(
    ppt: PptxGenJs, 
    slideTemplate: SlideTemplate, 
    data: any, 
    options: JsonToPptOptions,
    template?: PptTemplate,
    slideNumber?: number
  ): Promise<void> {
    const slide = ppt.addSlide();
    
    // 应用模板样式
    if (!template) {
      template = await this.templateManager.loadTemplate(options.templateName || 'default');
    }
    if (template.styles?.backgroundColor) {
      slide.background = { color: template.styles.backgroundColor.replace('#', '') };
      this.logger.debug('Applied background color to section slide', { 
        backgroundColor: template.styles.backgroundColor,
        processed: template.styles.backgroundColor.replace('#', '')
      });
    }
    
    // 添加装饰元素
    await this.addDecorationElements(slide, ppt, template);

    // 添加章节标题
    const title = this.templateManager.replacePlaceholders(slideTemplate.title, data);
    
    slide.addText(title, {
      x: 1,
      y: 2.5,
      w: 11.33, // 16:9宽度适配
      h: 1.2,
      fontSize: options.fontSize?.title || 28,
      bold: true,
      color: template.styles?.titleColor?.replace('#', '') || '16537e',
      align: 'center'
    });

    // 处理占位符
    if (slideTemplate.placeholders) {
      await this.addPlaceholdersToSlide(slide, slideTemplate.placeholders, data, ppt);
    }
  }

  /**
   * 创建内容幻灯片
   */
  private async createContentSlide(
    ppt: PptxGenJs, 
    slideTemplate: SlideTemplate, 
    data: any, 
    options: JsonToPptOptions,
    template?: PptTemplate,
    slideNumber?: number
  ): Promise<void> {
    const slide = ppt.addSlide();
    
    // 应用模板样式
    if (!template) {
      template = await this.templateManager.loadTemplate(options.templateName || 'default');
    }
    if (template.styles?.backgroundColor) {
      slide.background = { color: template.styles.backgroundColor.replace('#', '') };
      this.logger.debug('Applied background color to content slide', { 
        backgroundColor: template.styles.backgroundColor,
        processed: template.styles.backgroundColor.replace('#', '')
      });
    }
    
    // 添加装饰元素
    await this.addDecorationElements(slide, ppt, template);

    // 添加标题
    const title = this.templateManager.replacePlaceholders(slideTemplate.title, data);
    
    const titleY = slideTemplate.layout?.titlePosition === 'center' ? 2.5 : 0.5;
    slide.addText(title, {
      x: 0.5,
      y: titleY,
      w: 12.33, // 16:9宽度适配
      h: 1,
      fontSize: options.fontSize?.title || 20,
      bold: true,
      color: template.styles?.titleColor?.replace('#', '') || '16537e',
      align: slideTemplate.layout?.contentAlignment || 'left'
    });

    // 处理占位符
    if (slideTemplate.placeholders) {
      await this.addPlaceholdersToSlide(slide, slideTemplate.placeholders, data, ppt);
    }

    // 添加页码（如果启用）
    if (options.includePageNumbers && slideNumber) {
      slide.addText(`${slideNumber}`, {
        x: 12.5, // 16:9宽度适配
        y: 6.8,  // 16:9高度适配
        w: 0.5,
        h: 0.3,
        fontSize: 10,
        color: 'ffffff'
      });
    }
  }

  /**
   * 向幻灯片添加占位符内容
   */
  private async addPlaceholdersToSlide(
    slide: any, 
    placeholders: Record<string, PlaceholderConfig>, 
    data: any,
    ppt?: PptxGenJs
  ): Promise<void> {
    for (const [key, config] of Object.entries(placeholders)) {
      const value = data[key];
      
      if (value === undefined || value === null) {
        this.logger.debug('Placeholder value not found', { key, availableKeys: Object.keys(data) });
        continue;
      }

      // 转换位置为数字（支持百分比）
      const position = this.convertPosition(config.position);

      switch (config.type) {
        case 'text':
          await this.addTextPlaceholder(slide, value, position, config);
          break;
        case 'list':
          await this.addListPlaceholder(slide, value, position, config);
          break;
        case 'image':
          await this.addImagePlaceholder(slide, value, position, config);
          break;
        case 'table':
          await this.addTablePlaceholder(slide, value, position, config);
          break;
        case 'shape':
          if (ppt) {
            await this.addShapePlaceholder(slide, value, position, config, ppt);
          } else {
            this.logger.warn('PPT instance not available for shape placeholder', { key });
          }
          break;
        case 'chart':
          if (ppt) {
            await this.addChartPlaceholder(slide, value, position, config, ppt);
          } else {
            this.logger.warn('PPT instance not available for chart placeholder', { key });
          }
          break;
        default:
          this.logger.warn('Unknown placeholder type', { type: config.type, key });
      }
    }
  }

  /**
   * 添加文本占位符
   */
  private async addTextPlaceholder(
    slide: any, 
    value: any, 
    position: { x: number; y: number; w: number; h: number }, 
    config: PlaceholderConfig
  ): Promise<void> {
    const textValue = Array.isArray(value) ? value.join('\n') : String(value);
    
    slide.addText(textValue, {
      ...position,
      fontSize: config.style?.fontSize || 12,
      color: config.style?.color?.replace('#', '') || 'ffffff',
      bold: config.style?.bold || false,
      italic: config.style?.italic || false,
      align: 'left', // 16:9宽屏下使用左对齐更自然
      wrap: true
    });
  }

  /**
   * 添加列表占位符
   */
  private async addListPlaceholder(
    slide: any, 
    value: any, 
    position: { x: number; y: number; w: number; h: number }, 
    config: PlaceholderConfig
  ): Promise<void> {
    let listItems: string[] = [];
    
    if (Array.isArray(value)) {
      listItems = value.map(String);
    } else if (typeof value === 'string') {
      // 尝试按换行符或数字前缀分割
      if (value.includes('\n')) {
        listItems = value.split('\n').filter(item => item.trim());
      } else if (/^\[?\d+\]/.test(value)) {
        // 匹配 [1]xxx [2]xxx 格式
        listItems = value.split(/\[\d+\]/).filter(item => item.trim()).map(item => item.trim());
      } else {
        listItems = [value];
      }
    } else {
      listItems = [String(value)];
    }

    const bulletPoints = listItems.map(item => ({
      text: item,
      options: { 
        bullet: true,
        indentLevel: 0 
      }
    }));

    slide.addText(bulletPoints, {
      ...position,
      fontSize: config.style?.fontSize || 12,
      color: config.style?.color?.replace('#', '') || 'ffffff',
      bold: config.style?.bold || false,
      align: 'left' // 16:9宽屏下使用左对齐
    });
  }

  /**
   * 添加图片占位符
   */
  private async addImagePlaceholder(
    slide: any, 
    value: any, 
    position: { x: number; y: number; w: number; h: number }, 
    config: PlaceholderConfig
  ): Promise<void> {
    try {
      const imagePath = String(value);
      
      slide.addImage({
        path: imagePath,
        ...position
      });
    } catch (error) {
      this.logger.warn('Failed to add image placeholder', { value, error });
      // 添加图片占位符文本
      slide.addText(`[图片: ${value}]`, {
        ...position,
        fontSize: 12,
        color: '999999',
        italic: true
      });
    }
  }

  /**
   * 添加表格占位符
   */
  private async addTablePlaceholder(
    slide: any, 
    value: any, 
    position: { x: number; y: number; w: number; h: number }, 
    config: PlaceholderConfig
  ): Promise<void> {
    try {
      let tableData: any[][] = [];
      
      if (Array.isArray(value)) {
        if (Array.isArray(value[0])) {
          // 二维数组
          tableData = value;
        } else {
          // 一维数组，转为单行表格
          tableData = [value.map(String)];
        }
      } else if (typeof value === 'object') {
        // 对象转为键值对表格
        tableData = Object.entries(value).map(([key, val]) => [key, String(val)]);
      } else {
        // 字符串，尝试解析为表格
        const lines = String(value).split('\n');
        tableData = lines.map(line => line.split(/\t|,/).map(cell => cell.trim()));
      }

      slide.addTable(tableData, {
        ...position,
        fontSize: config.style?.fontSize || 11,
        color: config.style?.color?.replace('#', '') || 'ffffff',
        border: { pt: 0.5, color: 'CCCCCC' }
      });
    } catch (error) {
      this.logger.warn('Failed to add table placeholder', { value, error });
      // 添加表格占位符文本
      slide.addText(`[表格数据: ${JSON.stringify(value).substring(0, 50)}...]`, {
        ...position,
        fontSize: 12,
        color: '999999',
        italic: true
      });
    }
  }

  /**
   * 转换位置配置
   */
  private convertPosition(position: { x: number | string; y: number | string; w: number | string; h: number | string }) {
    return {
      x: this.convertPositionValue(position.x, 'width'),
      y: this.convertPositionValue(position.y, 'height'),
      w: this.convertPositionValue(position.w, 'width'),
      h: this.convertPositionValue(position.h, 'height')
    };
  }

  /**
   * 转换位置值（支持百分比）
   */
  private convertPositionValue(value: number | string, dimension: 'width' | 'height' = 'width'): number {
    if (typeof value === 'number') {
      return value;
    }
    
    if (typeof value === 'string' && value.endsWith('%')) {
      const percentage = parseFloat(value.replace('%', ''));
      // 16:9宽屏格式：宽度 13.33英寸，高度 7.5英寸
      const maxWidth = 13.33; // LAYOUT_WIDE 宽度
      const maxHeight = 7.5;   // LAYOUT_WIDE 高度
      
      if (dimension === 'width') {
        return (percentage / 100) * maxWidth;
      } else {
        return (percentage / 100) * maxHeight;
      }
    }
    
    return parseFloat(String(value)) || 0;
  }

  /**
   * 应用全局样式
   */
  private applyGlobalStyles(ppt: PptxGenJs, styles: any): void {
    // pptxgenjs的全局样式设置
    // 注意：实际实现需要根据pptxgenjs的API文档
  }

  /**
   * 应用主题
   */
  private applyTheme(ppt: PptxGenJs, theme: string): void {
    // 主题应用逻辑，与Markdown转换器相似
    const themes = {
      business: { backgroundColor: '#1E3A5F', titleColor: '#FFFFFF', textColor: '#E8F4FD' },
      modern: { backgroundColor: '#2C3E50', titleColor: '#3498DB', textColor: '#ECF0F1' },
      minimal: { backgroundColor: '#FAFAFA', titleColor: '#2C3E50', textColor: '#34495E' },
      default: { backgroundColor: '#FFFFFF', titleColor: '#2E75B6', textColor: '#333333' }
    };
    
    // 实际的主题应用需要根据pptxgenjs的API来实现
  }

  /**
   * 计算幻灯片数量
   */
  private calculateSlideCount(template: PptTemplate, data: any[]): number {
    let count = 0;
    
    for (const slide of template.slides) {
      if (slide.type === 'title' || slide.type === 'section') {
        count += 1;
      } else {
        count += data.length;
      }
    }
    
    return count;
  }

  /**
   * 添加装饰元素
   */
  private async addDecorationElements(
    slide: any,
    ppt: PptxGenJs,
    template: PptTemplate
  ): Promise<void> {
    const decorations = template.decorations;
    if (!decorations) return;
    
    // 添加左侧装饰线
    if (decorations.leftAccent) {
      const width = this.convertPositionValue(decorations.leftAccent.width, 'width');
      slide.addShape((ppt as any).shapes.RECTANGLE, {
        x: 0, y: 0, w: width, h: 7.5, // 16:9高度
        fill: {
          color: decorations.leftAccent.color.replace('#', ''),
          transparency: 0
        },
        line: { width: 0 }
      });
    }
    
    // 添加顶部遮罩
    if (decorations.headerOverlay) {
      const height = this.convertPositionValue(decorations.headerOverlay.height, 'height');
      slide.addShape((ppt as any).shapes.RECTANGLE, {
        x: 0, y: 0, w: 13.33, h: height, // 16:9宽度
        fill: {
          color: decorations.headerOverlay.color.replace('#', ''),
          transparency: decorations.headerOverlay.transparency
        },
        line: { width: 0 }
      });
    }
    
    // 添加角落装饰元素
    if (decorations.cornerElements && decorations.cornerElements.length > 0) {
      decorations.cornerElements.forEach((element, index) => {
        slide.addShape((ppt as any).shapes.RECTANGLE, {
          x: 10.5 + index * 0.5, y: 5.5 + index * 0.3, w: 2.5, h: 1.5, // 16:9适配
          fill: {
            color: element.color.replace('#', ''),
            transparency: element.transparency
          },
          line: { width: 0 }
        });
      });
    }
  }
  
  /**
   * 添加形状占位符
   */
  private async addShapePlaceholder(
    slide: any,
    value: any,
    position: { x: number; y: number; w: number; h: number },
    config: PlaceholderConfig,
    ppt: PptxGenJs
  ): Promise<void> {
    try {
      if (!config.shape) {
        this.logger.warn('Shape placeholder missing shape config', { config });
        return;
      }
      
      const shapeType = (ppt as any).shapes[config.shape.type] || (ppt as any).shapes.RECTANGLE;
      const shapeOptions: any = {
        ...position
      };
      
      if (config.shape.fill) {
        shapeOptions.fill = {
          color: config.shape.fill.color.replace('#', ''),
          transparency: config.shape.fill.transparency || 0
        };
      }
      
      if (config.shape.line) {
        shapeOptions.line = {
          color: config.shape.line.color?.replace('#', '') || 'ffffff',
          width: config.shape.line.width || 1
        };
      }
      
      slide.addShape(shapeType, shapeOptions);
      
    } catch (error) {
      this.logger.warn('Failed to add shape placeholder', { value, error });
    }
  }
  
  /**
   * 添加图表占位符
   */
  private async addChartPlaceholder(
    slide: any,
    value: any,
    position: { x: number; y: number; w: number; h: number },
    config: PlaceholderConfig,
    ppt: PptxGenJs
  ): Promise<void> {
    try {
      if (!config.chartType) {
        this.logger.warn('Chart placeholder missing chartType', { config });
        return;
      }
      
      // 准备图表数据
      let chartData: any[] = [];
      
      if (Array.isArray(value)) {
        chartData = value;
      } else if (value && typeof value === 'object') {
        // 如果是对象，尝试转换为图表数据格式
        chartData = this.convertDataToChartFormat(value, config.chartType);
      } else {
        this.logger.warn('Chart data format not supported', { value, chartType: config.chartType });
        return;
      }
      
      // 获取图表类型
      const chartType = ppt.ChartType[config.chartType as keyof typeof ppt.ChartType];
      if (!chartType) {
        this.logger.warn('Unknown chart type', { chartType: config.chartType });
        return;
      }
      
      // 准备图表选项
      const chartOptions: any = {
        x: position.x,
        y: position.y,
        w: position.w,
        h: position.h
      };
      
      // 应用样式配置
      if (config.style) {
        if (config.style.title) {
          chartOptions.title = config.style.title;
          chartOptions.showTitle = true;
        }
        
        if (config.style.titleColor) {
          chartOptions.titleColor = config.style.titleColor.replace('#', '');
        }
        
        if (config.style.chartArea) {
          chartOptions.chartArea = config.style.chartArea;
        }
        
        if (config.style.plotArea) {
          chartOptions.plotArea = config.style.plotArea;
        }
        
        if (config.style.showLegend !== undefined) {
          chartOptions.showLegend = config.style.showLegend;
        }
        
        if (config.style.legendPos) {
          chartOptions.legendPos = config.style.legendPos;
        }
        
        // 轴标签颜色
        if (config.style.catAxisLabelColor) {
          chartOptions.catAxisLabelColor = config.style.catAxisLabelColor.replace('#', '');
        }
        
        if (config.style.valAxisLabelColor) {
          chartOptions.valAxisLabelColor = config.style.valAxisLabelColor.replace('#', '');
        }
        
        if (config.style.dataLabelColor) {
          chartOptions.dataLabelColor = config.style.dataLabelColor.replace('#', '');
        }
        
        // 特定图表类型的样式
        if (config.chartType === 'pie') {
          if (config.style.showValue !== undefined) {
            chartOptions.showValue = config.style.showValue;
          }
          if (config.style.showPercent !== undefined) {
            chartOptions.showPercent = config.style.showPercent;
          }
        }
        
        if (config.chartType === 'line' && config.style.lineSize) {
          chartOptions.lineSize = config.style.lineSize;
        }
      }
      
      // 添加图表
      slide.addChart(chartType, chartData, chartOptions);
      
      this.logger.debug('Chart added successfully', { 
        chartType: config.chartType, 
        dataLength: chartData.length,
        position 
      });
      
    } catch (error) {
      this.logger.warn('Failed to add chart placeholder', { value, config, error });
      
      // 添加错误占位符
      slide.addText(`[图表: ${config.chartType}]\n数据加载失败`, {
        ...position,
        fontSize: 12,
        color: '999999',
        italic: true,
        align: 'center'
      });
    }
  }
  
  /**
   * 转换数据到图表格式
   */
  private convertDataToChartFormat(data: any, chartType: string): any[] {
    if (chartType === 'pie') {
      // 饼图数据格式
      if (data.values && data.labels) {
        return data.values.map((value: number, index: number) => ({
          name: data.labels[index] || `项目${index + 1}`,
          labels: [data.labels[index] || `项目${index + 1}`],
          values: [value]
        }));
      }
      
      // 对象键值对转饼图
      if (typeof data === 'object' && !Array.isArray(data)) {
        return Object.entries(data).map(([key, value]) => ({
          name: key,
          labels: [key],
          values: [Number(value)]
        }));
      }
    }
    
    if (chartType === 'bar' || chartType === 'line' || chartType === 'area') {
      // 柱状图、折线图、面积图数据格式
      if (data.series && Array.isArray(data.series)) {
        return data.series.map((series: any) => ({
          name: series.name,
          labels: data.labels || series.labels,
          values: series.values
        }));
      }
      
      // 简单数组数据
      if (data.values && data.labels) {
        return [{
          name: data.name || '数据系列',
          labels: data.labels,
          values: data.values
        }];
      }
    }
    
    if (chartType === 'scatter') {
      // 散点图数据格式
      if (data.series && Array.isArray(data.series)) {
        return data.series.map((series: any) => ({
          name: series.name,
          values: series.values // 应该是 [[x,y], [x,y], ...] 格式
        }));
      }
    }
    
    // 默认返回空数组
    return [];
  }
  
  /**
   * 保存PPT文件
   */
  private async savePpt(ppt: PptxGenJs, outputPath: string): Promise<void> {
    return new Promise((resolve, reject) => {
      ppt.writeFile({ fileName: outputPath })
        .then(() => {
          this.logger.debug('PPT file saved successfully', { outputPath });
          resolve();
        })
        .catch(error => {
          this.logger.error('Failed to save PPT file', createErrorLogContext(error, { outputPath }));
          reject(error);
        });
    });
  }
}
